﻿using Puerts;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using TTEngine;
using TTEngine.Graphics;
using TTEngine.Impl.Avalonia;
using TTEngine.Resource;
using TTEngine.TTMath;
using voidbox.Code.JSEngine;

namespace voidbox.Code
{
    public class VBApp : IDisposable
    {
        public readonly VBAppConfig Config;


        System.IO.Compression.ZipArchive zip = null;
        public CommonResource gfx_resource;
        public TTEngine.Graphics.Batcher gfx_batcher;

        JsEngine jsEngine;

        public Color clearColor = Color.Black;
        public VBApp(string path)
        {
            this.Path = path;

            this.Config = new VBAppConfig();
            this.Config.Init(this.LoadText("app.ini"));

            Debuger.Enable = this.Config.Debug;

        }
        public bool IsPack
        {
            get;
            private set;
        }
        public string Path
        {
            get;
            private set;
        }
        public void CallOnTouch(int touchid, bool press, float x, float y)
        {
            jsEngine?.callOnPoint?.InvokeOnPoint(touchid, press, x, y);
        }
        public void CallOnKey(int key, bool press)
        {
            jsEngine?.callOnKey?.InvokeOnKey(key, press);
        }
        public void CallUpdate(float delta)
        {
            jsEngine.ClearCall();
            jsEngine?.Tick();
            this.jsEngine?.callupdate?.InvokeUpdate(delta);
            gfx_resource.PackedTextureGroup.ApplyTextureData();
        }
        public void CallRender()
        {
            Runtime.activeTarget.Clear(this.clearColor);
            try
            {
                this.jsEngine?.callrender?.InvokeRender();
            }
            catch (Exception err)
            {
                Debug.WriteLine(err.Message);
            }
            gfx_batcher.EndDraw();
            //Runtime.activeTarget.RenderInfo.DrawStats(gfx_resource, gfx_batcher.GetPackedTextureBatcher(), new fAABB(0, 0, 200, 64), 1, true);
            Debuger.SetStat("callcount","callcount="+ jsEngine.CallCount);
        }
        public void Dispose()
        {
            if (zip != null)
            {
                zip.Dispose();
            }

            TTEngine.Resource.ResourcePackage.DestoryPackage(gfx_resource.Package, true);
            gfx_resource = null;
            jsEngine?.Dispose();
            jsEngine = null;

        }
        public byte[] LoadBinary(string filename)
        {
            if (!IsPack)
            {
                return System.IO.File.ReadAllBytes(System.IO.Path.Combine(Path, filename));
            }
            else
            {
                var entry = zip.GetEntry(filename);
                var bytes = new byte[entry.Length];
                using var ms = entry.Open();
                ms.Read(bytes, 0, bytes.Length);
                return bytes;
            }
        }
        public string LoadText(string filename)
        {
            if (!IsPack)
            {
                return System.IO.File.ReadAllText(System.IO.Path.Combine(Path, filename));
            }
            else
            {
                var bts = LoadBinary(filename);
                return System.Text.Encoding.UTF8.GetString(bts);
            }
        }

        //读取配置文件，初始化绘制
        public void Init()
        {
            
            jsEngine = new JsEngine();
            
            if (System.IO.File.Exists(Path))
            {
                IsPack = true;
                zip = System.IO.Compression.ZipFile.OpenRead(Path);
            }
            else if (System.IO.Directory.Exists(Path))
            {
                IsPack = false;
            }
            else
            {
                throw new Exception("给定的路径既不是Pack 也不是目录，无法加载App");
            }
            this.gfx_resource = new CommonResource();
            this.gfx_resource.Init(TTEngine.Resource.ResourcePackage.Create());
            this.gfx_batcher = new TTEngine.Graphics.Batcher(this.gfx_resource);
            if (this.Config.DebugPort > 0)
            {
                jsEngine?.Init(this.Config.DebugPort);
            }

            Root.SetOutputSize(Config.PixelWidth, Config.PixelHeight);

            var win = (TTEngine.API.view as GLMainView).GetWindow();
            if (win != null)
                win.Title = "VoidBox8 " + this.Config.Title;


            foreach (var jsfile in Config.LoadJs)
            {
                string jstxt = null;
                try
                {
                    jstxt = LoadText(jsfile);

                }
                catch (Exception err)
                {
                    Debuger.AddLog("[syserr]" + "加载JS文件错误:" + jsfile + " " + err.Message);
                }
                if (jstxt != null)
                {
                    try
                    {
                        jsEngine?.Execute(jsfile, jstxt);
                        Debuger.AddLog("[sys]" + "已加载JS文件:" + jsfile);
                    }
                    catch (Exception err)
                    {
                        Debuger.AddLog("[syserr]" + "执行JS文件错误:" + jsfile + " " + err.Message);
                    }
                }
            }
        }

        //恢复是在加载了多个app 关闭了后面的才会发生
        public void ToTop()
        {
            if (this.Config.Debug)
            {
                jsEngine?.StartDebug(5566);
            }

        }
        //Stop 切到后台

        public void ToBack()
        {
            if (this.Config.Debug)
            {
                jsEngine?.StopDebug();
            }
        }
        public void Reload()
        {
            Dispose();

            Init();

            ToTop();
        }
        public void Gfx_DrawSprite(ushort index, Color32 color, Vector3 pos, Vector2 scale, float rotate)
        {
            PackedTextureElementInst elem = new PackedTextureElementInst();
            elem.ElemID = index;
            elem.color = Color32.White;
            elem.pos = pos;
            elem.scale = scale;
            elem.rotate = rotate;
            gfx_batcher.GetPackedTextureInstanceBatcher().AddElementInst(elem);
        }
    }
}
